# 装饰器
"""
装饰器：
    原则：遵循开放封闭原则，在不改变原函数的情况下，扩展了函数功能
    特点：
        1. 日志、权限校验、缓存
        2. 统计
    定义：
        def aaa(func):
            def xxx(参数，...):
                ....
                func()
                ...
            return xxx
    装饰：
        @aaa
        def 原函数（）：
            pass

    代参数装饰器：*arg，**kwargs
        原函数有参数，装饰器必须也有参数
        *arg：可变参数
        **kwargs：关键字参数
    装饰器修饰有返回值的函数：
        原函数有返回值，wrapper中必须有返回值

再入装饰器：



"""


def foo():
    print("foo")


def func():
    print("func")


foo = func  # 函数名仅仅是一个变量，相当于变量赋值，地址发生改变

foo()

print("装饰器".center(20, "#"))


def deco_house(fu):
    """
    1. 定义装饰器:装修房子
    :param fu : 被装饰着的引用
    :return wrapper : 返回被装饰后的对象 的地址  ；相当于house_a 装饰前后的地址发生变化
    相当于house_a = house-----地址指向发生改变----->house_a = wrapper
    """
    def wrapper():
        fu()
        print("安装家电----->")
        print("安装床沙发----->")
        print("精装修完成----->")

    return wrapper  # 返回内部函数


@deco_house  # 就会调用deco_house函数--->house_a = deco_house(house_a)
def house_a():
    print("毛坯房A")


@deco_house
def house_b():
    print("毛坯房B")


house_a()
house_b()

print("带参数的装饰器".center(30, '*'))


def de_house(fu):
    def wrapper(*args, **kwargs):  # wrapper() got an unexpected keyword argument 'name'：（name="香格里拉大酒店"）  修改添加**kwargs
        fu(*args, **kwargs)  # fu 就是house;元组拆包（带星拆元组）：*args
        print("安装家电----->")
        print("安装床沙发----->")
        print("精装修完成----->")

    return wrapper  # 返回内部函数


@de_house
def house(address):
    print("房子的地址在:{}，是一个毛坯房".format(address))


@de_house
def chang_fang(address, area):
    print("房子的地址在:{}，是一个毛坯房。建筑面积是:{}平米".format(address, area))


@de_house
def hotel(name, address, area=40):
    print("{}的地址在:{}，是一个毛坯房。单间建筑面积是:{}平米".format(name, address, area))


house("西安钟楼")

print("--------------------------")

chang_fang("西安雁塔区", 130)
print("------------默认参数--------------")
hotel("全季大酒店", "西安雁塔区")
print("------------指定默认参数--------------")
hotel("全季大酒店", "西安雁塔区", 80)
print("----------关键字参数----------------")
hotel(name="全季大酒店", address="西安雁塔区", area=80)
print("----------关键字参数：修改顺序----------------")
hotel(address="西安高新区", name="香格里拉大酒店", area=150)

print("装饰器修饰有返回值的函数".center(30, '*'))


def make_house(fu):
    def wrapper(*args, **kwargs):  # wrapper() got an unexpected keyword argument 'name'：（name="香格里拉大酒店"）  修改添加**kwargs
        r = fu(*args, **kwargs)  # fu 就是house;元组拆包（带星拆元组）：*args
        print("预计装修费用是：{}元".format(r))
        print("安装家电----->")
        print("安装床沙发----->")
        print("精装修完成----->")
        return r  # 原函数有返回值，wrapper中必须有返回值

    return wrapper


@make_house
def new_house():
    print("毛坯房....")
    return 50000


result = new_house()
print(result)
